home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Diamond Collection / The Diamond Collection (Software Vault)(Digital Impact).ISO / cdr48 / tsbat146.zip / BATRICKS.TXT < prev    next >
Text File  |  1995-01-30  |  35KB  |  943 lines

  1. Assorted Batch Tricks                                Mon 30-Jan-95
  2. =====================
  3.                                                All rights reserved
  4.                              Copyright (c) 1993-1995 by Timo Salmi
  5.  
  6. ..................................................................
  7. Prof. Timo Salmi      Co-moderator of comp.archives.msdos.announce
  8. Moderating at garbo.uwasa.fi anonymous FTP archives  193.166.120.5
  9. Faculty of Accounting & Industrial Management; University of Vaasa
  10. Internet: ts@uwasa.fi   BBS +(358)-61-3170972; FIN-65101,  Finland
  11. ..................................................................
  12.  
  13.   ┌───────────────────────────────────────────────────────────┐
  14.   │ This file belongs to TSBAT*.ZIP. Please do not distribute │
  15.   │ this batricks.txt file separately! If you see this file   │
  16.   │ alone on a BBS, please alert the SysOp immediately.       │
  17.   └───────────────────────────────────────────────────────────┘
  18.  
  19. Introduction
  20. ============
  21.  
  22. This file contains assorted batch tricks. Many, but not all, have
  23. been used in the TSBAT*.ZIP collection of batches. Likewise, there
  24. are some useful further tricks, not documented here, to be found in
  25. the TSBAT batches. Furthermore, many users have sent me useful
  26. suggestions and their own alternative solutions. My best thanks for
  27. the material. You can find much of this feedback stored in the
  28. garbo.uwasa.fi:/pc/pd2/tspost*.zip files.
  29.  
  30. You are free to quote brief passages from this file provided you
  31. clearly indicate the source with a proper acknowledgment.
  32.  
  33. Comments and corrections are solicited. But if you wish to have
  34. individual batch programming consultation, please rather post your
  35. question to a UseNet newsgroup like comp.os.msdos.programmer. It is
  36. much more efficient than asking me by email. I'd like to help, but I
  37. am very pressed for time. I prefer to pick the questions I answer
  38. from the Usenet news. Thus I can answer publicly at one go if I
  39. happen to have an answer. Besides, newsgroups have a number of
  40. readers who might know a better or an alternative answer. Don't be
  41. discouraged, though, if you get a reply like this from me. I am
  42. always glad to hear from fellow batch file users.
  43.  
  44.  
  45. INDEX
  46. =====
  47.  
  48. 1)  Making "@echo off" general
  49. 2)  Deleting all files
  50. 3)  Nested loops
  51. 4)  Checking whether a directory exists
  52. 5)  Checking that a program is available at the current directory or at path
  53. 6)  Using subroutines in batches
  54. 7)  Convert a parameter to uppercase
  55. 8)  Appending a new directory to the path
  56. 9)  Comparing two files
  57. 10) Writing an empty line
  58. 11) Customizing the pause message
  59. 12) Complicate renaming with for
  60. 13) Checking for wildcards
  61. 14) Preventing breaking the batch
  62. 15) Prevent a break from bypassing your autoexec.bat
  63. 16) Getting the extension
  64. 17) The quote character %
  65. 18) Eliminating auxiliary batches
  66. 19) Utilizing the subst command in paths
  67. 20) How to run a batch once a week (testing for the weekday)
  68. 21) Testing if a file name includes a path
  69. 22) Showing the time without enter
  70. 23) Alternatives for testing for the errorlevel value
  71. 24) Redirecting a batch file's output
  72. 25) Testing for environment space sufficiency
  73. 26) A simple trick to "disable" a drive
  74. 27) Sending an escape sequence to the printer
  75. 28) Creating a random string
  76. 29) Finding out the length of a string
  77. 30) How to obtain the MsDos version into an environment variable
  78. 31) Finding out the number of regular files on a drive
  79. 32) Augmenting line numbers to a text file
  80. 33) Storing and returning to the original directory (push and pop)
  81. 34) Enticing the current date into an environment variable
  82. 35) Identifying the individual PC
  83. 36) For loop and redirection quirks
  84. 37) Traversing a directory tree
  85. 38) Echoing the redirection symbol
  86. 39) Getting the file basename
  87.  
  88.  
  89. 1. Making "@echo off" general
  90. =============================
  91.  
  92. If you want to turn the echo off, and do not wish to show that line
  93. on the screen, you can easily do this by applying
  94.  @echo off
  95.  
  96. There is a catch, however, because this only works since MsDos
  97. version 3.30.  So if you want to make it general, put the following
  98. line in your autoexec.bat file if you are using MsDos 3.30 or higher
  99.  set _echo=@
  100. Then use the following format in your batches, which will then work
  101. for any MsDos version
  102.  %_echo%echo off
  103.  
  104.  
  105. 2. Deleting all files
  106. =====================
  107.  
  108. One of the most Frequently Asked Questions (FAQs) about batches is
  109. how to suppress the "Are you sure (Y/N)?" confirmation requirement
  110. for del *.*.  Use the following:
  111.  echo y| del *.*
  112. If you wish to suppress the message too, use
  113.  echo y| del *.* > nul
  114. There is also another alternative for doing this:
  115.  for %f in (*.*) do call del %f
  116. Whether or not it is sensible to suppress the confirmation can be
  117. debated, but these are the tricks anyway.
  118.  
  119.  
  120. 3. Nested loops
  121. ===============
  122.  
  123. It is possible to have nested loops of a kind in batch programming.
  124. Consider the following two batches, and try it out by calling
  125. test.bat.
  126.   echo off
  127.   rem TEST.BAT
  128.   for %%f in (a b c d e f) do %comspec% /c test2 %%f
  129.  
  130.   echo off
  131.   rem TEST2.BAT
  132.   for %%g in (1 2 3) do echo %1%%g
  133.  
  134. Alternatively write everything below on a single line
  135.   for %%f in (a b c d e f) do %comspec% /c
  136.     for %%g in (1 2 3) do echo %%f%%g
  137. (The wrap has been used in the text is because of the right margin.
  138. Don't wrap your batch.).  The disadvantage of this alternative is
  139. that the echo will be on.
  140.  
  141.  
  142. 4. Checking whether a directory exists
  143. ======================================
  144.  
  145. It is sometimes useful to be able to test whether a particular
  146. directory exists. The following test is true if the %1 directory
  147. does not exist.
  148.  if not exist %1\nul if not exist %1nul echo Directory %1 does not exist
  149.  
  150. Please note that just like many other items, this will not work on
  151. 4DOS or DR-DOS. These otherwise excellent alternatives have many
  152. hidden incompatibilities with vanilla MS-DOS.
  153.  
  154.  
  155. 5. Checking that a program is available at the current directory or at path
  156. ===========================================================================
  157.  
  158. When you call a program from a batch, and do not give the explicit
  159. path to it, it is advisable to test that the program is available
  160. either at the current directory or the default path.
  161.   set _found=
  162.   if exist %1 set _found=yes
  163.   for %%d in (%path%) do if exist %%d\%1 set _found=yes
  164.   for %%d in (%path%) do if exist %%d%1 set _found=yes
  165.   if "%_found%"=="yes" goto _continue
  166.   echo %1 is not at path or the current directory
  167.   goto _out
  168.   :_continue
  169.   echo %1 found at path or in the current directory
  170.   :_out
  171.  
  172.  
  173. 6. Using subroutines and recursion in batches
  174. =============================================
  175.  
  176. It is possible to use subroutines within batches. The crucial trick
  177. is setting an environment variable (e.g. _return) to point to a
  178. label where to return after the subroutine has been performed. For
  179. an example see UNPACK.BAT, and BOOT.BAT, the sections :_common and
  180. :_subru.
  181.  
  182. Likewise it is possible to use recursion go emulate subroutines in
  183. batches. (Recursion means that a batch calls itself).
  184. As an example see SAFEDEL.BAT and trace the effects of the line
  185.  for %%f in (%1) do call safedel %%f recurse
  186. Note that safedel could be replaced by %0 because the zeroth
  187. parameter of a batch file points to itself.
  188.  
  189.  
  190. 7. Convert a parameter to uppercase
  191. ===================================
  192.  
  193. This example shows how to ensure that the parameter %1 given to the
  194. batch is in uppercase. This utilizes the fact that MS-DOS converts
  195. the path to uppercase. The result is stored in upcase_ and then the
  196. original path is restored.
  197.   set tmp_=%path%
  198.   path=%1
  199.   set upcase_=%path%
  200.   path=%tmp_%
  201.   set tmp_=
  202.  
  203. The also is another method for getting case-independent results.
  204. This is adapted from Jeff Prosise's column in PC Computing, March
  205. 1993, pp. 216-217. If the batch below is called TEST.BAT, it makes
  206. no difference whether you enter "TEST yes" or "TEST YES" or "TEST
  207. yEs".
  208.   @echo off
  209.   if not "%1"=="" set %1=*****
  210.   set status_=
  211.   if "%yes%"=="*****" set status_=yes
  212.   if "%no%"=="*****" set status_=no
  213.   if not "%status_%"=="" echo The parameter %%1 was a %status_%
  214.   if "%status_%"=="" echo The parameter %%1 was neither a yes nor a no
  215.   if not "%1"=="" set %1=
  216.  
  217.  
  218. 8. Appending a new directory to the path
  219. ========================================
  220.  
  221. This often needed trick is basically very simple. For example
  222. to add directory %1 to path use
  223.  path=%path%;%1
  224. Note that you can only use this trick in a batch. It will not work
  225. at the MS-DOS prompt because the environment variables are expanded
  226. (%path%) only within batches.
  227.  
  228. For a full treatment with safeguards against appending non-existing
  229. directories, or appending twice, see ADDPATH.BAT.
  230.  
  231.  
  232. 9. Comparing two files
  233. ======================
  234.  
  235. It is possible in batch programming to test whether or not two files
  236. have identical contents. This trick utilizes the external MS-DOS
  237. programs fc.exe and find.exe.  (An external MS-DOS program means, of
  238. course, a program that comes with the standard MS-DOS releases. Most
  239. often the MS-DOS external support files are located in a c:\dos
  240. directory.)
  241.   fc %1 %2 > tmp$$$
  242.   type tmp$$$ | find /i "fc: no differences encountered" > diffe$$$
  243.   if exist notsame$ del notsame$
  244.   copy diffe$$$ notsame$ > nul
  245.   if not exist notsame$ echo Files %1 and %2 are different
  246.   if exist notsame$ echo Files %1 and %2 are identical
  247.   if exist tmp$$$ del tmp$$$
  248.   if exist notsame$ del notsame$
  249.   if exist diffe$$$ del diffe$$$
  250. If you think about, this idea can be used for other useful purposes,
  251. too, because it establishes whether a given string is found in a
  252. text file.
  253.  
  254.  
  255. 10. Writing an empty line
  256. =========================
  257.  
  258. This is a simple, but an often needed, useful trick.  Just use echo
  259. with (for example) a point (.) after it. As you can see, I have
  260. utilized this batch feature extensively in my batch collection.
  261.  echo.
  262.  
  263.  
  264. 11. Customizing the pause message
  265. =================================
  266.  
  267. You can easily customize the message given by pause by giving your
  268. own with echo and directing the pause message to nul.
  269. to nul.
  270.  echo Break to quit, any other key to remove the tmp directory
  271.  pause > nul
  272.  
  273.  
  274. 12. Complicate renaming with for
  275. ================================
  276.  
  277. Although this is basically trivial, one does not necessarily come to
  278. think of it. The for statement is quite useful for involved renaming
  279. of files. An example delineates. For example I have the following
  280. files (Turbo Pascal units for TP 4.0, 5.0, 5.5, 6.0 and 7.0).  Say
  281. that I wish to rename them to be version 33 instead of 32.
  282.   tspa3340.zip
  283.   tspa3350.zip
  284.   tspa3355.zip
  285.   tspa3360.zip
  286.   tspa3370.zip
  287. The following for-statement does that conveniently.
  288.  for %f in (40 50 55 60 70) do ren tspa32%f.zip tspa33%f.zip
  289. Naturally, renaming is not the only task that can utilize this
  290. trick. I am sure you can readily think of others, like
  291.   for %d in (a b) do format %d:
  292.  
  293.  
  294. 13. Checking for wildcards
  295. ==========================
  296.  
  297. This example shows how you can test whether a parameter (%1) of a
  298. batch contains wildcards.
  299.   @echo off
  300.   for %%f in (%1) do if "%%f"=="%1" goto _nowilds
  301.   echo Parameter %1 contains wildcards (or is missing)
  302.   :_nowilds
  303.  
  304.  
  305. 14. Preventing breaking the batch
  306. =================================
  307.  
  308. It is possible to prevent the user from interrupting a batch by
  309. using the ctty command to reassign the input (and the output)
  310. device. Here is an example (an elementary password batch requiring
  311. inputting an e). Note the < and > redirections which are needed
  312. while the ctty has been assigned to nul. The ask batch enhancer is
  313. included in the TSBAT collection.
  314.   @echo off
  315.   ctty nul
  316.   echo Now you cannot break the batch with ^C or ^Break > con
  317.   :_ask
  318.   echo Use e to break > con
  319.   ask /b /d < con
  320.   if errorlevel==101 if not errorlevel==102 goto _out
  321.   goto _ask
  322.   :_out
  323.   ctty con
  324.   echo Back to normal. Now you can break the batch with ^C or ^Break.
  325. Note that this trick does not prevent you from rebooting with
  326. alt-crtl-del while the batch is running. For that you need an
  327. external program like noboot.exe from garbo.uwasa.fi:/pc/ts/
  328. tstsr20.zip (or whichever version number is current).
  329.  
  330.  
  331. 15. Prevent a break from bypassing your autoexec.bat
  332. ====================================================
  333.  
  334. You can actually prevent a quick tapping of the break from bypassing
  335. your autoexec.bat by a variation of the trick in the item above. Put
  336. for example
  337.   shell=c:\command.com /p nul
  338. in your config.sys. Before you do, make sure to have a floppy to
  339. boot from in case something goes wrong. I first saw trick when it
  340. was posted in the UseNet comp.os.msdos.programmer newsgroup by
  341. Joseph Gil yogi@cs.ubc.ca.
  342.  
  343. This is not, however, quite all there is to it.  You should put
  344.   ctty con
  345. as the last line to your autoexec.bat.  If you don't, the keyboard
  346. will not be responding, and you must boot from the floppy you so
  347. sensibly had prepared :-).
  348.  
  349.  
  350. 16. Getting the extension
  351. =========================
  352.  
  353. It would be quite useful to be able to extract the extension of a
  354. given file name into an environment variable. Or to be able just to
  355. test whether there is an extension. Here is how to do that. The
  356. batch is based on the information in PC-Magazine July 1992, Vol. 11,
  357. No. 13, page 528. It gives the crucial information that if one
  358. precedes the argument of a for loop with a slash (/), then the
  359. argument is interpreted in two parts. The first part is the first
  360. character of the argument, the second part all the rest. Neat,
  361. indeed.
  362.    The problem with my solution below is that it will not recognize
  363. .* or .??? as extensions. But, of course, one can first test for
  364. wildcards as shown in a previous item "Checking for wildcards". See
  365. e.g. UNPACK.BAT for the utilization of this method.
  366.      @echo off
  367.      set exten_=%1
  368.      :_next
  369.      set prev_=%exten_%
  370.      for %%f in (/%exten_%) do set exten_=%%f
  371.      if ".%exten_%"=="%prev_%" goto _extfound
  372.      if not "%exten_%"=="%prev_%" goto _next
  373.      goto _noext
  374.      :_extfound
  375.      echo The filename %1 has an extension %exten_%
  376.      goto _out
  377.      :_noext
  378.      echo The filename %1 has no extension
  379.      :_out
  380.      set exten_=
  381.      set prev_=
  382.  
  383.  
  384. 17. The quote character %
  385. =========================
  386.  
  387. As we know %1 indicates the first parameter given to a batch. Thus
  388. for example echo %1 echoes that parameter.  But what if you want to
  389. echo the actual string %1 instead.  The % character acts as a quote
  390. character. Thus echo %%1 will indeed be a "%1" instead of its usual
  391. interpretation. Try the following simple test
  392.   @echo off
  393.   if "%1"=="" goto _out
  394.   echo %1
  395.   echo %%1
  396.   :_out
  397. See the item on "Eliminating auxiliary batches" for utilizing this
  398. feature. A good example of utilizing this feature is given by
  399. DELPATH.BAT.
  400.  
  401.  
  402. 18. Eliminating auxiliary batches
  403. =================================
  404.  
  405. Quite a number of batch programming tasks require an auxiliary batch
  406. which the primary batch has to call. Many of these cases can be
  407. eliminated by making the batch call itself (a kind of recursion).
  408. The auxiliary code is put in the batch itself. The trick is best
  409. illustrated by looking at the SHOW.BAT, which provides a wild-carded
  410. TYPE command, and would normally need an auxiliary file to type each
  411. of the individual files. Another example is given by the SAFEDEL.BAT
  412. batch.
  413.    There is also an another trick for a similar purpose. The primary
  414. batch creates and auxiliary batch or batches, which it then calls.
  415. See DELPATH.BAT for an example of this method. Here is also a simple
  416. demonstration listing the drives on your system.  (Only from c to t,
  417. actually because of the wrap I use here).
  418.  @echo off
  419.  echo @echo off> tmp$$$.bat
  420.  echo if exist %%1:\nul echo Drive %%1: is present>> tmp$$$.bat
  421.  for %%d in (c d e f g h i j k l m n o p q r s t) do call tmp$$$ %%d
  422.  del tmp$$$.bat
  423.    There was an inventive twist of this method in PC-Magazine August
  424. 1992, Vol. 11, No. 14, p. 527 for getting the volume label of a
  425. disk.  Here is my own example using the same techniques. It sets the
  426. current directory in an environment variable getdir_. I have
  427. utilized this technique in PUSHDIRE.BAT.
  428.   @echo off
  429.   echo @echo off> director.bat
  430.   echo set getdir_=%%2>> director.bat
  431.   echo echo %%getdir_%%>> director.bat
  432.   dir | find "Directory"> go.bat
  433.   call go
  434.   if exist director.bat del director.bat
  435.   if exist go.bat del go.bat
  436.  
  437.  
  438. 19. Utilizing the subst command in paths
  439. ========================================
  440.  
  441. I use the following kind of a simple batch to make some of my
  442. directories easy to reach. The way this simple batch is written it
  443. avoids unnecessary errors if the substitution already has been made.
  444. As a last measure it shows the current substitution status.
  445.   @echo off
  446.   if exist m:\nul echo The substitution has already been made
  447.   if not exist m:\nul subst m: c:\math
  448.   if not exist s:\nul subst s: c:\support
  449.   subst
  450.  
  451.  
  452. 20. How to run a batch once a week (testing for the weekday)
  453. ============================================================
  454.  
  455. The crucial trick is to be able to put the weekday into an
  456. environment variable. For the full treatment see WEEKLY.BAT. The
  457. essential trick needed is below, that is capturing the weekday into
  458. a weekday_ environment variable. No auxiliary programs outside the
  459. normal MS-DOS commands are needed.
  460.   @echo off
  461.   echo.| date | find "Current" > tmp$$$.bat
  462.   echo set weekday_=%%3> current.bat
  463.   call tmp$$$
  464.   echo %weekday_%
  465.   if "%weekday_%"=="Fri" echo Thank God it's Friday
  466.   if exist tmp$$$.bat del tmp$$$.bat
  467.   if exist current.bat del current.bat
  468.   set weekday_=
  469. In fact, if you substitute %%4 for the %%3 in the above, you'll
  470. capture today's date. Neat, eh?
  471.  
  472.  
  473. 21. Testing if a file name includes a path
  474. ==========================================
  475.  
  476. First of all please see the earlier item "Getting the extension"
  477. because the same ideas are drawn upon. Testing whether the file name
  478. is a bare file name like go.exe or includes a path like
  479. r:\progs\go.exe is quite a complicated task if one wants to allow
  480. wildcarded names like r:\progs\*.exe.  This can be done, and here is
  481. how.  If one can figure this one out, one can safely say that one
  482. has begun to understand batch files.
  483.   @echo off
  484.   echo @echo off> tmp$$$.bat
  485.   echo set rest_=%%1>> tmp$$$.bat
  486.   echo :_next>> tmp$$$.bat
  487.   echo set prev_=%%rest_%%>> tmp$$$.bat
  488.   echo for %%%%g in (/%%rest_%%) do set rest_=%%%%g>> tmp$$$.bat
  489.   echo if ":%%rest_%%"=="%%prev_%%" goto _found>> tmp$$$.bat
  490.   echo if "\%%rest_%%"=="%%prev_%%" goto _found>> tmp$$$.bat
  491.   echo if not "%%rest_%%"=="%%prev_%%" goto _next>> tmp$$$.bat
  492.   echo goto _nopath>> tmp$$$.bat
  493.   echo :_found>> tmp$$$.bat
  494.   echo set haspath_=yes>> tmp$$$.bat
  495.   echo goto _out>> tmp$$$.bat
  496.   echo :_nopath>> tmp$$$.bat
  497.   echo set haspath_=no>> tmp$$$.bat
  498.   echo :_out>> tmp$$$.bat
  499.   echo set rest_=>> tmp$$$.bat
  500.   echo set prev_=>> tmp$$$.bat
  501.   for %%f in (%1) do call tmp$$$ %%f
  502.   if "%haspath_%"=="yes" echo Filename %1 includes a path
  503.   if "%haspath_%"=="no" echo Filename %1 does not include a path
  504.   rem if exist tmp$$$.bat del tmp$$$.bat
  505.   set haspath_=
  506.  
  507.  
  508. 22. Showing the time without enter
  509. ==================================
  510.  
  511. A simple trick to show the current time:
  512.   echo.| time | find /v "new"
  513. For capturing the time into an environment variable see
  514. LASTBOOT.BAT.
  515.  
  516.  
  517. 23. Alternatives for testing for the errorlevel value
  518. =====================================================
  519.  
  520. Many programs and some MS-DOS commands (like diskcomp, format and
  521. xcopy) return an errorlevel exit code on termination. Testing for
  522. the errorlevel is complicated by the cumulative nature of
  523. errorlevels. Thus if you wish to test if the errorlevel was
  524. (exactly) 2, you must use
  525.  if errorlevel==2 if not errorlevel==3 echo Errorlevel 2
  526. Another alternative is utilizing the for command:
  527.  for %%e in (0 1 2 3 4 5 6 7) do if errorlevel==%%e set _errlev=%%e
  528.  if "%_errlev%"=="2" echo Errorlevel 2
  529. Alternatively, and more generally
  530.  for %%e in (0 1 2 3 4 5 6 7) do if errorlevel==%%e set _errlev=%%e
  531.  if "%_errlev%"=="2" echo Errorlevel %_errlev%
  532. A convenient trick in more complicated batches is using the goto
  533. command:
  534.   for %%e in (0 1 2) do if errorlevel==%%e goto _label%%e
  535.   goto _out
  536.   :_label0
  537.   echo Errorlevel 0
  538.   :_label1
  539.   echo Errorlevel 1
  540.   :_label2
  541.   echo Errorlevel 2
  542.   :_out
  543. See BOOT.BAT for actual usage of this technique.
  544.  
  545.  
  546. 24. Redirecting a batch file's output
  547. =====================================
  548.  
  549. Output from within a batch file is easily redirected. Consider a
  550. batchfile example.bat with the following contents
  551.   @echo This is a redirection test> test
  552. Running "example" will produce a file "test" with
  553.   This is a redirection test
  554. The line has an eoln (end of line: ascii 13 + 10) at the end.
  555. Note that it often is advisable not to leave any blank in front of
  556. the > redirection operator.
  557.  
  558. Redirecting the output that a batch produces, is more complicated.
  559. Consider a batchfile example2.bat with the following contents
  560.   @echo This is another redirection test
  561. Running
  562.   example2 > test
  563. will produce an empty "test" file, while the text is echoed on the
  564. standard output. To redirect the output, you need to drive the batch
  565. through the command interpreter command.com like this (provided that
  566. command.com is at path or in the current directory).
  567.   command /c example2 > test
  568. This will redirect the text to the "test" file.
  569.  
  570. There is another quirk of redirection in MS-DOS batch programming
  571. best demonstrated by an example:
  572.   @echo off
  573.   rem This line will create an empty tmp.$$ file > tmp.$$
  574.   :: This line will not create an empty tmp.$$$ file > tmp.$$$
  575.   rem This line will cause problems: Press <ESC>
  576.   :: This line will not cause problems: Press <ESC>
  577. As explained in PC Magazine Vol 12, Number 9, November 9, 1993, the
  578. reason is that the :: is taken as a label and not processed while
  579. the rem basically is an MS-DOS command that will be processed. The
  580. processing will start from the redirection at the end. This is the
  581. the also reason why redirection and the MS-DOS FOR command will
  582. cause problems. (See the entry "For loop and redirection quirks".)
  583.  
  584.  
  585. 25. Testing for environment space sufficiency
  586. =============================================
  587.  
  588. If your batch utilizes environment variables there is a possibility
  589. that you run out of environment space.  If you get an "Out of
  590. environment space" message the well-known trick to increase your
  591. environment space by using shell configuration in config.sys:
  592.   Example: shell=c:\bin\command.com c:\bin /e:1024 /p
  593.  
  594. A perhaps less-known trick is that you can test in advance if your
  595. batch will run out of environment space. Below is an example showing
  596. you how to test if you have an additional 32 bytes of environment
  597. space still available for your batch:
  598.  @echo off
  599.  set test_=12345678901234567890123456789012
  600.  if "%test_%"=="12345678901234567890123456789012" goto _yes
  601.  echo Insufficient environment space
  602.  goto _out
  603.  :_yes
  604.  echo Sufficient environment space
  605.  set test_=
  606.  rem Whatever you wish to do
  607.  :_out
  608.  
  609.  
  610. 26. A simple trick to "disable" a drive
  611. =======================================
  612.  
  613. It you wish temporarily disable a drive use the subst command for
  614. example as follows
  615.   @echo off
  616.   md c:\none
  617.   subst d: c:\none
  618. To enable it again use
  619.   @echo off
  620.   subst d: /d
  621.   rd c:\none
  622.  
  623.  
  624. 27. Sending an escape sequence to the printer
  625. =============================================
  626.  
  627. Here is a truly trivial trick. You cannot send escape sequences to
  628. the printer directory from the command line, but it is quite easy to
  629. do that from a simple batch file:
  630.   @echo ESC%1> prn
  631. where you have to replace the ESC by the true escape character using
  632. your preferred editor. One snag with this methods is that it imposes
  633. a linefeed.
  634.  
  635.  
  636. 28. Creating a random string
  637. ============================
  638.  
  639. I was asked on the UseNet news how to create a random string. My
  640. reply.  Please study the following example and expand on it
  641.   @echo off
  642.   echo 10 randomize(val(mid$(time$,7,2))) > tmp.bas
  643.   echo 20 open "tmp2.bat" for output as #1 >> tmp.bas
  644.   echo 30 x$ = mid$(str$(int(rnd*10000)),2) >> tmp.bas
  645.   echo 40 print #1,"@set random_=";x$ >> tmp.bas
  646.   echo 50 close #2 >> tmp.bas
  647.   echo 60 system >> tmp.bas
  648.   gwbasic tmp.bas
  649.   call tmp2
  650.   del tmp.bas
  651.   del tmp2.bat
  652.   set
  653.  
  654.  
  655. 29. Finding out the length of a string
  656. ======================================
  657.  
  658. The task of finding out the length of a string was tackled in PC
  659. Magazine January 26, 1993 issue. The solution is my own and more
  660. general, but naturally it has similar ingredients to the PC
  661. Magazine's.
  662.   @echo off
  663.   set test_=Testing the length of a string
  664.   echo %test_% > len$&$&$
  665.   dir len$&$&$ | find "LEN$&$&$" > go$$$.bat
  666.   echo @echo off> len$&$&$.bat
  667.   echo set length_=%%1>> len$&$&$.bat
  668.   call go$$$
  669.   echo The length is %length_% bytes
  670.   del len$&$&$
  671.   del len$&$&$.bat
  672.   del go$$$.bat
  673.  
  674.  
  675. 30. How to obtain the MsDos version into an environment variable
  676. ================================================================
  677.  
  678. Here is the code how to do it.
  679.   @echo off
  680.   ver > go$$$.bat
  681.   echo @echo off> ms-dos.bat
  682.   echo set version_=%%2>> ms-dos.bat
  683.   call go$$$
  684.   echo Your MsDos version is %version_%
  685.   del go$$$.bat
  686.   del ms-dos.bat
  687.  
  688. MS-DOS 5.0 version introduced many enhancements (like the loadhigh
  689. command, etc) and additions to the command switches (like /B and /S
  690. to the DIR command). Therefore it is useful to be able to test
  691. whether the batch is being run on a system that is at least MS-DOS
  692. 5.0. Below is one option.
  693.   rem Establish whether MS-DOS version 5.0 or later is being used
  694.   set isver50_=
  695.   ver | find "5.0" > tmpfind.$$$
  696.   ver | find "6.0" >> tmpfind.$$$
  697.   ver | find "6.2" >> tmpfind.$$$
  698.   copy tmpfind.$$$ tmpfind1.$$$ > nul
  699.   del tmpfind.$$$
  700.   if exist tmpfind1.$$$ set isver50_=yes
  701.   if exist tmpfind1.$$$ del tmpfind1.$$$
  702.  
  703.  
  704. 31. Finding out the number of regular files on a drive
  705. ======================================================
  706.  
  707. Try
  708.   attrib /s c:\*.* | find /c "\"
  709. The directories will not be (mis)counted as files as would with the
  710. dir command. Besides the dir command is not recursive until MS-DOS
  711. version 5.0.
  712.   Note that if you do this for the same drive where you reside,
  713. you'll get one too many in the count because of the "|" pipe.
  714.  
  715.  
  716. 32. Augmenting line numbers to a text file
  717. ==========================================
  718.  
  719. Occasionally it might be useful to put line number to a text file.
  720. Here is an example how to do it with MS-DOS commands only
  721.   type YourFile.txt | find /v /n "&$&$&$123" > YourNew.txt
  722. The parameter &$&$&$123 stands for an improbable string, since find
  723. /v means displaying all the lines not containing it.
  724.  
  725.  
  726. 33. Storing and returning to the original directory (push and pop)
  727. =================================================================
  728.  
  729. There are several methods for (non-resident) pushing and popping the
  730. directory by batch file techniques. In other words storing the
  731. current directory, changing the directory in between, and then
  732. returning to the starting directory. PUSHDIRE.BAT and POPDIRE.BAT
  733. give one method where the current drive and directory are stored in
  734. environment variables. The second method, displayed below, is a
  735. direct adaptation from Jeff Prosise's column in PC Computing, March
  736. 1993, pp. 216-217. Later the trick was presented again in Pc
  737. Magazine June 14, 1994, Vol. 13, No. 11, p. 357. The method is a
  738. very clever utilization of the prompt system. An example
  739. illustrates.
  740.   @echo off
  741.   echo @prompt cd $p$_$n:> r:\setback.bat
  742.   %comspec% /c r:\setback> r:\goback.bat
  743.   ::
  744.   rem Change the drive and directory
  745.   c:
  746.   cd \dos
  747.   echo The current directory is
  748.   cd
  749.   rem Do whatever you wish to do there
  750.   pause
  751.   ::
  752.   rem Go back to the original drive and directory
  753.   call r:\goback
  754.   echo Now back in the original directory
  755.   ::
  756.   rem cleanup
  757.   if exist r:\setback.bat del r:\setback.bat
  758.   if exist r:\goback.bat del r:\goback.bat
  759.  
  760.  
  761. 34. Enticing the current date into an environment variable
  762. ==========================================================
  763.  
  764. Like in the item "Storing and returning to the original directory"
  765. there are more than one way of doing this. One method is indicated
  766. in the item "How to run a batch once a week". The other (again)
  767. utilizes the prompt:
  768.   @echo off
  769.   echo @prompt set date_=$d> r:\tmp$$$.bat
  770.   %comspec% /c r:\tmp$$$> r:\tmp2$$$.bat
  771.   call r:\tmp2$$$
  772.   echo %date_%
  773.   del r:\tmp$$$.bat
  774.   del r:\tmp2$$$.bat
  775.  
  776. If you look at your MS-DOS manual for the prompt special $ codes
  777. (like $d) that you can use in the prompt, you'll see that this
  778. method opens quite a number of possibilities of putting information
  779. into environment variables. Exercise: Put the current weekday into
  780. an environment variable. Hint: Apply $d and $h.
  781.  
  782.  
  783. 35. Identifying the individual PC
  784. =================================
  785.  
  786. In cases of some batches it is useful to identify the PC the batch
  787. is run on. For example I use several different PCs myself and
  788. occasionally I need to differentiate between them. The solution is
  789. really trivial. Set an environment variable in the autoexec.bat to
  790. designate the PC. I use a variable pcid_ for this purpose. An
  791. outline batch illustrates.
  792.   @echo off
  793.   if "%pcid_%"=="" goto _none
  794.   goto %pcid_%
  795.   :dell
  796.   echo Dell 325N laptop, do whatever
  797.   goto _out
  798.   :trifu
  799.   echo Trifunic 386 desktop, do whatever
  800.   goto _out
  801.   :karvi
  802.   echo "Garfunkel" Pinus 486 desktop, do whatever
  803.   goto _out
  804.   :_none
  805.   echo PC not identified, do whatever
  806.   :_out
  807. For example in the autoexec.bat of my DELL 325N laptop I have
  808.   set pcid_=dell
  809.  
  810.  
  811. 36. For loop and redirection quirks
  812. ===================================
  813.  
  814. A question from Newsgroups: comp.os.msdos.misc,comp.os.msdos.programmer
  815. > I am using DOS 5.0 and I have the following line in my batch file:
  816. > for %%f in (a b c d) do if exist %%f echo put %%f >> tmpfile
  817. > where a,b,c,d are some filenames.
  818. >
  819. > What I expect it to do is to echo the lines
  820. >  put a
  821. >  put b
  822. >  put c
  823. >  put d
  824. > into the file tmpfile.
  825. >
  826. > But what happen is after the "put a" is written to tmpfile, the rest of the
  827. > lines will just echo to the screen, look like that the redirection is not
  828. > working.
  829. >
  830. > If I take away the "if exist" everything is working fine.  I found out
  831. > every time when I use a conditional statement with redirection, it will
  832. > only redirect the first time, the rest will echo to the screen.
  833. >
  834. > Is it the for loop cannot be mixed with the conditional statement and the
  835. > redirection?
  836.  
  837. Yes, it can be mixed, but not so simply in this case. Use the
  838. following batch
  839.   @echo off
  840.   del tmpfile
  841.   for %%f in (a b c d) do if exist %%f call auxil %%f
  842. where auxil.bat contains
  843.   @echo off
  844.   echo put %1>> tmpfile
  845. I'll be darned if I know why :-).
  846.  
  847. In fact it is possible to do this with a single batch by employing
  848. the following method described in an earlier item
  849.   @echo off
  850.   echo @prompt echo put %%%%1$g$g tmpfile> tmp$$$.bat
  851.   %comspec% /c tmp$$$> auxil.bat
  852.   if exist tmpfile del tmpfile
  853.   for %%f in (a b c d) do if exist %%f call auxil %%f
  854.   del tmp$$$.bat
  855.   del auxil.bat
  856.  
  857.  
  858. 37. Traversing a directory tree
  859. ===============================
  860.  
  861. Traversing it straight up is relatively easy as can be seen from
  862. this example.
  863.   @echo off
  864.   :_loop
  865.   dir/w
  866.   if not exist ..\nul goto _out
  867.   cd ..
  868.   goto _loop
  869.   :_out
  870. Going recursively down through a directory and its subdirectories is
  871. very complicated. Yet it can be done if you have MS-DOS 5.00 or
  872. beyond. The SWEEP.BAT batch accompanying tsbat*.zip demonstrates
  873. how. The method is, however, too difficult to be of real practical
  874. importance. It is getter to use an auxiliary program for sweeping,
  875. like garbo.uwasa.fi:/pc/filefind/target15.zip or SWEEP.COM from
  876. /pc/pcmagvol/vol4n24.zip.
  877.  
  878.  
  879. 38. Echoing the redirection symbol
  880. ==================================
  881.  
  882. In certain situations would be useful to be able echo the
  883. redirection symbol rather than have its perform its redirection
  884. function. For example your batch file might have a help line like
  885. this
  886.   echo The line to customize is "echo dir/w %%%%3\%%2 >> %%new_%%"
  887. As you see the double quotes pre-empt the redirection. If you left
  888. them out, the line would result create a file %NEW_% containing
  889. "The line to customize is echo dir/w %%3\%2".
  890.    Contrary to Unix, \ cannot be used to cover the special meaning
  891. of a symbol. As explained in the item "The quote character %" the %
  892. sign, can as is demonstrated above by the %% pairs. But %> does not
  893. take precedence over the redirection.
  894.  
  895.  
  896. 39. Getting the file basename
  897. =============================
  898.  
  899. Occasionally one needs to get the file name without the extension.
  900. Just like getting the extension from a file name using the "for %%f
  901. in (/%exten_%)" trick, even this can be done with batch commands
  902. only. The batch code for getting the basename has been presented by
  903. Neil Rubenking in PC Magazine April 26, 1994, Vol. 13, No. 8, pp.
  904. 275-276. But enough is enough even with batch tricks. The logic is
  905. getting overly complicated. One has to draw the line somewhere, stop
  906. kidding oneself, and start using batch enhancers (external programs
  907. to help out). I think here the limit has been reached. Hence I have
  908. included "basename" and "basepath" programs, which you can use to
  909. create the enhancers. They return the relevant information into an
  910. environment variable with that name.
  911.    When you come to think of it. From one viewpoint, what else than
  912. batch enhancers are all the external MS-DOS commands (usually) in
  913. your C:\DOS directory?
  914.    Using basename and basepath is very easy. Below is an example
  915.        @echo off
  916.        basename r:\cmand\command.com
  917.        basepath r:\cmand\command.com
  918.        echo %basename%
  919.        echo %basepath%
  920. You can discard the environment variable simply by applying (note
  921. the two alternatives):
  922.        set basename=
  923.        basepath
  924. There is also a "basexten" batch enhancer in the /pc/ts/tsbat*.zip
  925. collection.
  926.  
  927.  
  928. Literature
  929. ==========
  930.  
  931. Most books on batch programming, which I have seen, are too
  932. elementary to be really useful to the readers of this file. Hence
  933. this list is very brief indeed.
  934.  
  935. Jamsa, Kris (1993). Concise Guide to MS-DOS Batch Files. Microsoft
  936.   Press. (Draws heavily on DEBUG, but might be of general interest
  937.   to you.)
  938.  
  939. Some issues of magazines like the PC Magazine and PC Computing have
  940. contained much useful MS-DOS lore. But they have gradually become so
  941. heavily Windows oriented that they are losing their interest and
  942. usefulness to an MS-DOS user.
  943.